<template>
  <div :class="treePos?'treeCon':'notPos'">
    <a-tree
      v-if="menuData.length"
      :disabled="optFlag==3"
      show-line
      show-icon
      :checkable="checkable"
      :expanded-keys="expandedKeys"
      :auto-expand-parent="autoExpandParent"
      :tree-data="menuData"
      :replace-fields="replaceFields"
      :checkStrictly="checkStrictly"
      :selectedKeys="defaultSelectedKeys"
      @expand="onExpand"
      v-model="mymenuIds"
      @select="selectTree"
      @check="treeCheck"
    ></a-tree>
  </div>
</template>

<script>
import { menuByCondition, unitTree, selectData } from "@/api/component";

export default {
  data() {
    return {
      mymenuIds: [],
      menuData: [],
      expandedKeys: [],
      autoExpandParent: true,
      replaceFields: {
        key: 'id',
        title: 'name'
      },
      myCount:0
    };
  },
  props: {
    defaultSelectedKeys:{//默认树节点蓝色选中节点
      type: Array,
      default: null
    },
    halfFlag: {
      type:Boolean,//是否保存半选值
      default:false
    },
    isThreeFalse: { //三权分立是否固定传false
      type: Boolean,
      default: false
    },
    seletedCount: {//计算子节点
        type: Number,
        default: 0
    },
    single:{//复选框是否单选
      type: Boolean,
      default: false
    },
    checkFunc:{ //勾选复选框
      type: Function,
      default: ()=>{}
    },
    checkStrictly:{//复选框上下级是否关联
      type: Boolean,
      default: false
    },
    selectFunc:{ //选择树
      type: Function,
      default:()=>{}
    },
    selectId:{ //选中的id
      type: String
    },
    checkable:{ //是否选中
      type: Boolean,
      default: true
    },
    treePos:{//是否定位
      type: Boolean,
      default:true
    },
    menuIds: {  //选中的数组
      type: Array,
      default: () => []
    },
    optFlag: { //状态
      // 1新增 2编辑 3查询
      type: Number,
      default: 1
    },
    requestFlag:{//请求哪一个接口
        type: Number,
        default: 1
    },
    toData:{//直接传递数据无需接口
        type: Array,
        default: () => []
    },
  },
  mounted() {
    if(this.requestFlag==1){ //菜单含按钮所有
      this.getMenuList();
    }
    if(this.requestFlag==2){ //部门
      this.unitTree()
    }
    if(this.requestFlag==3){ //角色授权
        this.setMenuData(this.toData, "id", "parentId", "children");
        this.initdata()
    }
    if(this.requestFlag==4){//单位
      this.commonTree('g');
    }
    if(this.requestFlag==5){//工作组
      this.commonTree('t')
    }
    if(this.requestFlag==6){//角色
      this.commonTree('r')
    }
    if(this.requestFlag==7){ //职位授权
        this.setMenuData(this.toData, "id", "parentId", "children");
        this.initdata()
    }
    if(this.requestFlag==8){//机构下菜单树不带按钮
      this.myCount = this.seletedCount;
      this.getNavData();
    }
    if(this.requestFlag==9){//机构下菜单树带按钮
      this.myCount = this.seletedCount;
      this.rootTree();
    }   
  },
  methods: {
    //树 复选框勾选
    treeCheck(checkedKeys,e){
      if(this.requestFlag===4||this.requestFlag===5||this.requestFlag===6){
        if(this.single&&this.mymenuIds.checked.length>1){
          this.mymenuIds.checked.shift();
        }
        this.$emit('checkFunc',this.requestFlag,this.mymenuIds.checked,e.node);
      }
      if(this.halfFlag){
        let pArr = e.node.pos.split('-'),
            isLeaf = e.node.isLeaf,
            checked = e.checked;
        //获取当前节点对象 tempObj
        pArr.shift();
        let tempObj = this.menuData[pArr[0]];
        if(isLeaf&&checked){
          this.controlParent(tempObj.id);//顶层父节点选中
        }
        pArr.shift();
        if(pArr.length){
          pArr.forEach((p,i)=>{
            tempObj = tempObj.children[p];
            if(isLeaf&&checked&&i!=pArr.length-1){
              this.controlParent(tempObj.id);//中间父节点选中
            }
          })
        }
        if(!isLeaf){
          this.controlChild(tempObj.children,checked);
        }
      }
    },
    //树数据选择
    selectTree(value,e){
      if(value.length){
        if(this.requestFlag===4||this.requestFlag===5||this.requestFlag===6){
          this.$emit('selectFunc',this.requestFlag,value[0],e.node.isLeaf);
        }
        if(this.requestFlag===8){
          let tempArr = this.handelKey(this.deepFind(this.menuData,value[0],'children'),'children');
          this.$emit('selectFunc',tempArr[0]);
        }
      }
    },
    //父节点控制  子节点全选或全不选
    controlChild(myArr,checked){
      var $this = this;
      // 用try方案方便直接中止所有递归的程序
      try {
          // 开始轮询
          (function poll(myArr) {
              // 遍历数组
              for (let i = 0; i < myArr.length; i++) {
                  let index = $this.mymenuIds.checked.findIndex(m=>m===myArr[i].id);
                  if(!checked){
                    if(index>-1){//删除已勾选
                      $this.mymenuIds.checked.splice(index,1);
                    }
                  }else{
                    if(index<0){//添加未勾选
                      $this.mymenuIds.checked.push(myArr[i].id);
                    }
                  }
                  //如果存在children，那么深入递归
                  if (myArr[i].children&&myArr[i].children.length) {
                    poll(myArr[i].children,checked);
                  }
              }
          })(myArr, 0)
      // 使用try/catch是为了中止所有轮询中的任务
      } catch (err) {}
    },
    //子节点控制父节点 若子节点选中 相关父节点未选中的置为选中
    controlParent(id){
      if(this.mymenuIds.checked.findIndex(m=>m===id)<0){
        this.mymenuIds.checked.push(id);
      }
    },
     /**
     * 深度递归搜索
     * @param {Array} arr 你要搜索的数组
     * @param {value} value 搜索的判定值
     * @param {String} children 子数组的key
     */
    deepFind(arr, value, children){
        // 即将返回的数组
        let main = [],
            myArr = JSON.parse(JSON.stringify(arr));
        // 用try方案方便直接中止所有递归的程序
        try {
            // 开始轮询
            (function poll(myArr, level) {
                // 如果传入非数组
                if (!Array.isArray(myArr)) return
                // 遍历数组
                for (let i = 0; i < myArr.length; i++) {
                    // 获取当前项
                    const item = myArr[i]

                    // 先占位预设值
                    main[0] = item

                    // 如果已经找到了
                    if (item.id===value) {
                        // 直接抛出错误中断所有轮询
                        throw Error
                    // 如果存在children，那么深入递归
                    } else if (children && item[children] && item[children].length) {
                        main = []
                        poll(item[children], level + 1)
                    // 如果是最后一个且没有找到值，那么通过修改数组长度来删除当前项
                    } else if (i === myArr.length - 1) {
                      // 删除占位预设值
                      main = []
                    }
                }
            })(myArr, 0)
        // 使用try/catch是为了中止所有轮询中的任务
        } catch (err) {}
        // 返回最终数组
        return main
    },
    //设置key值
    handelKey(arr,children){
      var $this = this,
          myArr = JSON.parse(JSON.stringify(arr));
      // 即将返回的数组
        // 用try方案方便直接中止所有递归的程序
        try {
            // 开始轮询
            (function poll(myArr) {
                // 如果传入非数组
                if (!Array.isArray(myArr)) return
                // 遍历数组
                for (let i = 0; i < myArr.length; i++) {
                    $this.myCount++;
                    myArr[i].key = 'selectTree_'+$this.myCount;
                    // 如果存在children，那么深入递归
                    if (children && myArr[i][children] && myArr[i][children].length) {
                        poll(myArr[i][children])
                    }
                }
            })(myArr, 0)
        // 使用try/catch是为了中止所有轮询中的任务
        } catch (err) {}
        // 返回最终数组
        return myArr
    },
    //设置节点全部展开
    expandedAll(myArr,children){
        var $this = this;
        try {
            (function poll(myArr) {
                if (!Array.isArray(myArr)) return
                for (let i = 0; i < myArr.length; i++) {
                    $this.expandedKeys.push(myArr[i].id);
                    if (children && myArr[i][children] && myArr[i][children].length) {
                        poll(myArr[i][children])
                    }
                }
            })(myArr, 0)
        } catch (err) {}
    },
    onExpand(expandedKeys) {
      this.expandedKeys = expandedKeys;
      this.autoExpandParent = false;
    },
     //处理菜单树数据格式
    setMenuData(data,idFieldName,pidFieldName, childname){
        let cloneData = JSON.parse(JSON.stringify(data)); // 对源数据深度克隆
        var repeatArr = [];//记录树结构待移除的多余对象
        var wholeData = cloneData.filter((father)=>{//循环所有项
            let branchArr = cloneData.filter((child,index)=>{
                if(this.requestFlag===8){
                  child.scopedSlots = { title: 'name' };
                }
                if(father[idFieldName] === child[pidFieldName]){
                  repeatArr.push(index);
                }
                return father[idFieldName] == child[pidFieldName]//返回每一项的子级数组
            });
            if(branchArr.length>0){
                father[childname] = branchArr;//如果存在子级，则给父级添加一个children属性，并赋值
                if(this.requestFlag!==8){
                  father.isLeaf = false;
                }
            }else{
              if(this.requestFlag!==8){
                father.isLeaf = true;//设为叶子节点
              }
            }
            if(this.requestFlag==7&&father.type!='user'){ //控制只能选人
              father.disabled=true
            }
            if(this.requestFlag===8){
              father.scopedSlots = { title: 'name' };
            }
            return true;
        });
        this.menuData = wholeData.filter((father,i)=>{return !repeatArr.includes(i)});
    },
    initdata(){
        let $this = this;
        this.mymenuIds = this.menuIds;
        //自动展开菜单权限节点
        const expandedKeys = this.mymenuIds.map(item => {
            return $this.getParentKey(item, $this.menuData);
        }).filter((item, i, self) => item && self.indexOf(item) === i);
        Object.assign($this.$data, {
            expandedKeys,
            autoExpandParent: true,
        });
    },
    //获取扩展父节点key
    getParentKey(id,tree){
      let parentKey,
          $this = this;
      for (let i = 0; i < tree.length; i++) {
          const node = tree[i];
          if (node.children) {
              if (node.children.some(item => item.id === id)) {
                  parentKey = node.id;
              } else if ($this.getParentKey(id, node.children)) {
                  parentKey = $this.getParentKey(id, node.children);
              }
          }
      }
      return parentKey;
    },
    //获取菜单权限数据
    getMenuList() {
      this.loading = true;
        menuByCondition({hasSeparate:this.isThreeFalse?false:undefined,hasButton:true,rootId:JSON.parse(localStorage.getItem('userInfo')).rootId}).then(res => {
          this.setMenuData(res.data.data, "id", "parentId", "children");
          this.initdata()
        })
        .catch(err => {
          this.$message.destroy();
            this.$message.error(err);
        })
        .finally(() => {
          this.loading = false;
        });
    },
    //获取导航菜单树
    getNavData(){  //独立机构下不带按钮
        this.loading = true;
        menuByCondition({hasButton:false,rootId:JSON.parse(localStorage.getItem('userInfo')).rootId}).then(res => {
          this.setMenuData(res.data.data, "id", "parentId", "children");
          this.expandedAll(res.data.data,'children');
        })
        .catch(err => {
          this.$message.destroy();
            this.$message.error(err);
        })
        .finally(() => {
          this.loading = false;
        });
    },
    rootTree(){
        this.loading = true;
        menuByCondition({hasButton:true,rootId:JSON.parse(localStorage.getItem('userInfo')).rootId}).then(res => {
          this.setMenuData(res.data.data, "id", "parentId", "children");
          this.initdata()
        })
        .catch(err => {
          this.$message.destroy();
            this.$message.error(err);
        })
        .finally(() => {
          this.loading = false;
        });
    },
    unitTree(){//部门树
        this.loading = true;
        unitTree()
        .then((res) => {
          this.setMenuData(res.data.data, "id", "parentId", "children");
          this.initdata()
        })
        .catch((err)=>{
            this.$message.destroy();
            this.$message.error(err);
        })
        .finally(() => {
            this.loading = false;
        });
    },
    //获取单位/工作组/角色
    commonTree(type){
       this.loading = true;
        selectData({rootId:'',show:type,type:type}).then((res) => {
          let data = res.data.data;
          if(type==='r'){
            this.setRoleData(data.roleList);
            this.initdata();
          }else{
            this.setMenuData(type==='g'?data.unitList:data.teamList, "id", "parentId", "children");
            this.initdata();
          }
        }).catch((err)=>{
            this.$message.destroy();
            this.$message.error(err);
        }).finally(() => {
            this.loading = false;
        });
    },
    //将角色数据转为树形数据
    setRoleData(data){
       this.menuData = data.filter((item)=>{
         item.parentId = -1;
         item.isLeaf = true;
         return 1===1;
       });
    },
    getData(){
      if(this.halfFlag){
        return this.mymenuIds.checked
      }else{
        return this.mymenuIds
      }
    },
  },
  computed: {},
  watch: {
    menuIds(n) {
      this.mymenuIds = n;
      if(this.requestFlag===1){
        this.initdata();
      }
    },
    seletedCount(n){
      this.myCount = n;
    }
  }
};
</script>

<style lang="stylus" scoped>
@import '~stylus/mixin.styl';
.treeCon 
  overflow-y auto
  pos(52px, 0, 0, 15px, 1, 0)
.notPos
  model(100%, 100%, none, 5px 10px, -1, 3)
</style>